package com.firebird.fekpsl.socket.server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ServerRunnable implements Runnable {

	private Socket socket;
	private BufferedReader reader;
	private String msg="";
	private SocketService socketService;
	private String msgformatString="utf-8";
	private boolean recept=true;

	public ServerRunnable(Socket socket,SocketService ss){
		this.socket=socket;
		try {
			reader=new BufferedReader(new InputStreamReader(socket.getInputStream(),msgformatString));
			msg=socket.getLocalAddress().toString();
			System.out.println(msg);
			socketService=ss;
			sendMessage("服务器已连接");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(recept){
			try {
				if(socket.isConnected()&&!socket.isInputShutdown()){
					if((msg=reader.readLine())!=null){
						if(msg.equals("close")){
							close();
							break;
						}else {
							System.out.println(msg);
							dataHandling(msg);
						}
					}else{
						close();
						break;
					}
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				try {
					socket.close();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		}
	}

	private void close(){
		try {
			socketService.remove(socket.getInetAddress().toString());
			socket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void sendMessage(String msg){
		System.out.println(msg);
		try {
			PrintWriter writer=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),msgformatString)),true);
			writer.println(msg);
			writer.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 数据处理
	 * @param msg
	 * @throws IOException
	 * @throws UnsupportedEncodingException
	 */
	private void dataHandling(String msg) throws UnsupportedEncodingException, IOException{
		String[] infos=msg.split(",");
		String header=infos[0];
		if (header.equals("outRoom")) {
			//此操作废弃
			outRoom(infos[1], infos[2]);
		}else
		if (header.equals("next")) {
			//本题答题结束，是否开启下一题
			socketService.saveIndexResult(infos[1], infos[2], infos[3], infos[4]);
			Map<String, String> result=socketService.getIndexAnswer(infos[1], infos[2]);
			if(result.size()==socketService.getRoom(infos[1]).size()){//如果所有的人都答题完毕了，则提示可以进行下一题
				sendMessageToAll(infos[1], "next");
			}else{
				allUserIsConnection(infos[1]);
			}
		}else if (header.equals("finishAll")) {
			//答题终止
			socketService.userFinished(infos[1], infos[2]);
			Map<String, String> finishMap=socketService.getUserFinishState(infos[1]);
			if(finishMap.size()==socketService.getRoom(infos[1]).size()){
				sendMessageToAll(infos[1], "finishAll");
			}
		}else if (header.equals("result")) {
			//答题结果
			socketService.addResultRoom(infos[1], infos[2], infos[3]);
			int size=socketService.getRoom(infos[1]).size();//房间容量
			Map<String, String> result=socketService.getRoomResult(infos[1]);
			if(size==result.size()){//如果房间大小与已有答案数量相当，即代表所有人答题完成
				String resultliString="result";
				for(Map.Entry<String, String> entry:result.entrySet()){
					resultliString+=","+entry.getValue();
				}
				sendMessageToAll(infos[1], resultliString);
				//将结果分发给各个成员之后，情况该房间的结果数据，防止缓存过多
				socketService.destroyResult(infos[1]);
			}

		}else if(header.equals("clear")){
			//退出房间，清理此房间的所有数据
			socketService.destroyRoom(infos[1]);
		}else if(header.equals("checkConnection")){
			//检查该房间内的所有成员的连接情况
			allUserIsConnection(infos[1]);
		}else if(header.equals("addRoom")){
			//加入房间
			addToRoom(infos[1], infos[2],infos[3]);
		}else if (header.equals("prepare")) {
			socketService.addMapPrepare(infos[1], infos[2], socket);
			prepareInfos(infos[1],infos[2]);
		}
	}


	/**
	 * 给房间你的每一个人发送消息
	 * @param roomId
	 * @param msg
	 * @throws IOException
	 * @throws UnsupportedEncodingException
	 */
	private void sendMessageToAll(String roomId,String msg) throws UnsupportedEncodingException, IOException{
		printLnLog("sendMessageToAll:"+msg);
		Map<String, Participator> mp=socketService.getRoom(roomId);
		for(Map.Entry<String, Participator> entry:mp.entrySet()){
			Socket socket=entry.getValue().getSocket();
			printLnLog("sendMessageToAll to user:"+entry.getKey());
			if(!socket.isClosed()){//如果当前用户的连接未关闭则发送消息
				PrintWriter writer=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),msgformatString)),true);
				writer.println(msg);
				writer.flush();
			}
		}
	}

	/**
	 * 检查所有用户的在线情况
	 * @param roomId
	 * @throws UnsupportedEncodingException
	 * @throws IOException
	 */
	private void allUserIsConnection(String roomId) throws UnsupportedEncodingException, IOException{
		String unconnString="prompt";
		int unconnSize=0;
		Map<String, Participator> mp=socketService.getRoom(roomId);
		for(Map.Entry<String, Participator> entry:mp.entrySet()){
			Socket socket=entry.getValue().getSocket();
			if(socket.isClosed()){//如果当前用户的连接未关闭则发送消息
				unconnSize++;
				unconnString+=","+entry.getKey()+"断连";
			}
		}
		printLnLog(unconnString);
		//存在断连用户则发送断连信息
		if(unconnSize>0){
			userUnconnection(roomId, unconnString, unconnSize);
		}
	}

	/**
	 * 发送断连信息
	 * @param roomId
	 * @param msg
	 * @param connectionSize
	 * @throws UnsupportedEncodingException
	 * @throws IOException
	 */
	private void userUnconnection(String roomId,String msg,int unconnSize) throws UnsupportedEncodingException, IOException{
		Map<String, Participator> mp=socketService.getRoom(roomId);
		if(unconnSize==mp.size()){
			//全部断连，则清理房间
			socketService.destroyRoom(roomId);
		}else{
			if(mp.size()-unconnSize==1){
				msg="victory,对手逃跑，恭喜您获得胜利";
			}
			List<String> keysList=new ArrayList<>();
			for(Map.Entry<String, Participator> entry:mp.entrySet()){
				Socket socket=entry.getValue().getSocket();
				if(!socket.isClosed()){//如果当前用户的连接未关闭则发送消息
					PrintWriter writer=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),msgformatString)),true);
					writer.println(msg);
					writer.flush();
				}else{
					//断连消息发送之后将断连的玩家清理出房间
					keysList.add(entry.getKey());
				}
			}
			for(int i=0;i<keysList.size();i++){
				mp.remove(keysList.get(i));
			}
			keysList.clear();keysList=null;
		}


	}

	/**
	 * 加入房间
	 * @param roomId
	 * @param userId
	 * @throws UnsupportedEncodingException
	 * @throws IOException
	 */
	private void addToRoom(String roomId,String userId,String userName) throws UnsupportedEncodingException, IOException{
		Map<String, Participator> map=socketService.getRoom(roomId);
		if(map!=null&&map.size()==4){//房间最多4个人，已满则给出提示
			sendMessage("hasAll");
			return;
		}
		Participator tor=new Participator();
		tor.setUserId(userId);
		tor.setUserName(userName);
		tor.setSocket(socket);
		if(map!=null){//房间不为空
			String msg="";
			for (Map.Entry<String, Participator> entry:map.entrySet()) {//将房间内已加入人的信息发送给连接用户
				//返回数据包括，id，name,prepare,seatnumber
				msg+=","+entry.getKey()+","+entry.getValue().getUserName()+","+entry.getValue().isPrepare()+","+entry.getValue().getSeatNumber();
			}
			//当前用户
			Participator p=map.get(userId);
			if(p==null){//不在房间内
				//将连接上的用户的信息发送给所有的人
				sendMessageToAll(roomId, "newOnRoom,"+userId+","+userName+","+map.size());
				tor.setSeatNumber(map.size());
				sendMessage("roomInfo,"+map.size());//发送座位号
			}else {
				tor.setSeatNumber(p.getSeatNumber());
				tor.setPrepare(p.isPrepare());
				sendMessageToAll(roomId, "newOnRoom,"+userId+","+userName+","+p.getSeatNumber()+","+map.size());
				map.remove(userId);
			}
			//将房间内的所有人的数据发送给当前连接上的用户
			sendMessage("allOfRoom,"+msg);
		}else {
			//发送座位号（按加入房间的次序）
			sendMessage("roomInfo,"+0);
			tor.setSeatNumber(0);
		}
		//加入房间
		socketService.addToRoom(roomId, userId, tor);

	}

	/**
	 * 准备数据
	 * @param roomId
	 * @throws IOException
	 * @throws UnsupportedEncodingException
	 */
	private void prepareInfos(String roomId,String userId) throws UnsupportedEncodingException, IOException{
		sendMessageToAll(roomId, "prepare,"+userId);
		Map<String, Socket> prepareMap=socketService.getPrepare(roomId);
		Map<String, Participator> allRoomMap=socketService.getRoom(roomId);
		socketService.getRoom(roomId).get(userId).setPrepare(true);
		printLnLog(prepareMap.size()+"");
		printLnLog(allRoomMap.size()+"");
		if(prepareMap.size()>1 && prepareMap.size()==allRoomMap.size()){
			//如果房间内的准备人数与房间内所有人数一致，则开始答题
			printLnLog("start");
			sendMessageToAll(roomId, "start");
		}
	}

	private void printLnLog(String msg){
		System.out.println(msg);
	}

	/**
	 * 退出房间
	 * @param roomId
	 * @param userId
	 * @throws IOException
	 * @throws UnsupportedEncodingException
	 */
	private void outRoom(String roomId,String userId) throws UnsupportedEncodingException, IOException{
		int seat=socketService.getRoom(roomId).get(userId).getSeatNumber();
		socketService.getRoom(roomId).remove(userId);
		sendMessageToAll(roomId, "outRoom,"+userId+","+seat);
		if(socketService.getRoom(roomId).size()==0){
			//房间内的所有人都退出了
			socketService.destroyRoom(roomId);
		}
	}

}
